import { FormDemos } from "@/lib/@docs/demos/src";
import { Layout } from "@/layout";
import { MDX_DATA } from "@/mdx";

export default Layout(MDX_DATA.formValues);

## Initial values

In most cases you should set `initialValues`:

```tsx
import { useForm } from "@mantine/form";

const form = useForm({
  mode: "uncontrolled",
  initialValues: {
    name: "",
    email: "",
  },
});
```

## setValues handler

With `form.setValues` you can set all form values, for example you can set values after you have received a response from the backend API:

<Demo data={FormDemos.setValues} />

## setValues partial

`form.setValues` can also be used to set multiple values at once, payload will be shallow merged with current values state:

```tsx
import { useForm } from "@mantine/form";

const form = useForm({
  mode: "uncontrolled",
  initialValues: { name: "", email: "", age: 0 },
});

form.setValues({ name: "John", age: 21 });
form.getValues(); // -> { name: 'John', email: '', age: 21 }
```

## Initialize form

When called `form.initialize` handler sets `initialValues` and `values` to the same value
and marks form as initialized. It can be used only once, next `form.initialize` calls
are ignored.

`form.initialize` is useful when you want to sync form values with backend API response:

<Demo data={FormDemos.initialize} />

Example with [TanStack Query](https://tanstack.com/query/latest) (react-query):

```tsx
import { useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
import { useForm } from "@mantine/form";

function Demo() {
  const query = useQuery({
    queryKey: ["current-user"],
    queryFn: () => fetch("/api/users/me").then((res) => res.json()),
  });

  const form = useForm({
    mode: "uncontrolled",
    initialValues: {
      name: "",
      email: "",
    },
  });

  useEffect(() => {
    if (query.data) {
      // Even if query.data changes, form will be initialized only once
      form.initialize(query.data);
    }
  }, [query.data]);
}
```

Note that `form.initialize` will erase all values that were set before it was called.
It is usually a good idea to set `readOnly` or `disabled` on all form fields before
`form.initialize` is called to prevent data loss. You can implement this with
[enhanceGetInputProps](/form/get-input-props/#enhancegetinputprops):

<Demo data={FormDemos.enhanceGetInputPropsForm} />

## setFieldValue handler

`form.setFieldValue` handler allows to set value of the field at given path:

<Demo data={FormDemos.setFieldValue} />

## reset handler

`form.reset` handler sets values to `initialValues` and clear all errors:

<Demo data={FormDemos.reset} />

## setInitialValues handler

`form.setInitialValues` handler allows to update `initialValues` after form was initialized:

```tsx
import { useEffect } from "react";
import { useForm } from "@mantine/form";

function Demo() {
  const form = useForm({
    mode: "uncontrolled",
    initialValues: {
      name: "",
      email: "",
    },
  });

  useEffect(() => {
    fetch("/api/user")
      .then((res) => res.json())
      .then((data) => {
        // Update initial values after form was initialized
        // These values will be used in form.reset
        // and to compare values to get dirty state
        form.setInitialValues(data);
        form.setValues(data);
      });
  }, []);
}
```

## transformValues

Use `transformValues` to transform values before they get submitted in `onSubmit` handler.
For example, it can be used to merge several fields into one or to convert types:

<Demo data={FormDemos.transformValues} />

## Get transformed values

You can get transformed values outside of `form.onSubmit` method by calling `form.getTransformedValues`.
It accepts `values` that need to be transformed as optional argument, if it is not provided, then
the result of `form.getValues()` transformation will be returned instead:

```tsx
import { useForm } from "@mantine/form";

function Demo() {
  const form = useForm({
    mode: "uncontrolled",
    initialValues: {
      firstName: "John",
      lastName: "Doe",
    },

    transformValues: (values) => ({
      fullName: `${values.firstName} ${values.lastName}`,
    }),
  });

  form.getTransformedValues(); // -> { fullName: 'John Doe' }
  form.getTransformedValues({
    firstName: "Jane",
    lastName: "Loe",
  }); // { fullName: 'Jane Loe' }
}
```

## onValuesChange

`onValuesChange` function is called every time form values change, use it
instead of `useEffect` to subscribe to form values changes:

<Demo data={FormDemos.onValuesChange} />

## form.watch

`form.watch` is an effect function that allows subscribing to changes of a
specific form field. It accepts field path and a callback function that is
called with new value, previous value, touched and dirty field states:

<Demo data={FormDemos.watch} />

Note that `form.watch` uses `useEffect` under the hood – all hooks rules apply.
For example, you cannot use `form.watch` conditionally or inside loops.

```tsx
function Demo() {
  const form = useForm({
    mode: "uncontrolled",
    initialValues: { name: "" },
  });

  // ❌ This will not work
  if (Math.random() > 0.5) {
    form.watch("name", ({ previousValue, value, touched, dirty }) => {
      console.log({ previousValue, value, touched, dirty });
    });
  }
}
```

## Get values type

```tsx
import { useForm } from "@mantine/form";

function Demo() {
  const form = useForm({ initialValues: { name: "", age: 0 } });

  // Get inferred form values type, will be `{ name: string; age: number }`
  type FormValues = typeof form.values;

  // Use values type in handleSubmit function or anywhere else
  const handleSubmit = (values: FormValues) => console.log(values);
}
```

## Get transformed values type

To get transformed values (output of [transformValues](#transformvalues)) use `TransformedValues` type.
It is useful when you want to create a custom submit function:

```tsx
import { TransformedValues, useForm } from "@mantine/form";

function Demo() {
  const form = useForm({
    mode: "uncontrolled",
    initialValues: {
      name: "",
      locationId: "2",
    },

    transformValues: (values) => ({
      ...values,
      locationId: Number(values.locationId),
    }),
  });

  type Transformed = TransformedValues<typeof form>;
  // -> { name: string, locationId: number }

  const handleSubmit = (values: TransformedValues<typeof form>) => {};

  return <form onSubmit={form.onSubmit(handleSubmit)} />;
}
```

## Set values type

By default, form values types will be inferred from `initialValues`.
To avoid that, you can pass type to `useForm` hook, this approach is useful when
types cannot be correctly inferred or when you want to provide more specific types:

```tsx
import { useForm } from "@mantine/form";

interface FormValues {
  name: string; // regular field, same as inferred type
  role: "user" | "admin"; // union, more specific than inferred string type

  // values that may be undefined or null
  // cannot be correctly inferred in strict mode
  age: number | undefined;
  registeredAt: Date | null;

  // Arrays that are empty cannot be inferred correctly
  jobs: string[];
}

function Demo() {
  const form = useForm<FormValues>({
    mode: "uncontrolled",
    initialValues: {
      name: "",
      role: "user",
      age: undefined,
      registeredAt: null,
      jobs: [],
    },
  });
}
```
